package com.xhwl.centiotdata.suppliersystem.dahuaIcc;

import cn.hutool.http.HttpException;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xhwl.centiotdata.pojo.constant.DaHuaIccConstant;
import com.xhwl.centiotdata.pojo.constant.StrConstant;
import com.xhwl.centiotdata.pojo.dto.dahua.SecurityDaHuaDTO;
import com.xhwl.centiotdata.utils.RedisUtils;
import com.xhwl.common.exception.ApplicationException;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.utils.StringUtils;
import com.xhwl.sdk.security.utils.RSAUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

@Service
public class GeneralDaHuaIccHandler {
    private static final Logger log = LoggerFactory.getLogger(GeneralDaHuaIccHandler.class);

    @Autowired
    private RedisUtils redisUtils;

    public SecurityDaHuaDTO getToken(Integer projectId, Integer productId, String ipAndPort, String loginName, String password, String clientId, String clientSecret) {
        ReentrantLock lock = new ReentrantLock();
        SecurityDaHuaDTO securityDaHuaDTO = null;
        lock.lock();
        try {
            String key = new StringBuffer(StrConstant.SUPPLIER_SYSTEM_TOKEN).append("-").append(projectId).append("-").append(productId).toString();
            Object value = redisUtils.get(key);
            if (value == null) {
                String publicKey = this.getPublicKey(ipAndPort);
                securityDaHuaDTO = this.login(ipAndPort, loginName, password,  publicKey, clientId, clientSecret);
                redisUtils.setWithMinute(key, JSONObject.toJSONString(securityDaHuaDTO), 4);
            } else {
                securityDaHuaDTO = JSON.parseObject((String) value, SecurityDaHuaDTO.class);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
        return securityDaHuaDTO;
    }

    private String getPublicKey(String ipAndPort) {
        JSONObject resultObject = this.get(ipAndPort + DaHuaIccConstant.PUBLIC_KEY_URL);
        log.error("---getPublicKey-----------"+resultObject);
        if ("false".equals(resultObject.getString("success"))) {
            log.error("【DahuaICC getPublicKey】path:{};errMsg:{}", DaHuaIccConstant.PUBLIC_KEY_URL, resultObject.getString("errMsg"));
            throw new BusinessException("DahuaICC getPublicKey failed!");
        }
        JSONObject data = JSON.parseObject(resultObject.getString("data"));
        return data.getString("publicKey");
    }

    private SecurityDaHuaDTO login(String ipAndPort, String loginName, String password, String publicKey, String clientId, String clientSecret) throws Exception {
        Map<String, Object> params = new HashMap();
        params.put("grant_type", "password");
        params.put("username", loginName);
        params.put("password", RSAUtil.encrypt("RSA", password, RSAUtil.loadPublicKeyFromString("RSA", publicKey), 117));
        params.put("client_id", clientId);
        params.put("client_secret", clientSecret);
        params.put("public_key", publicKey);
        JSONObject resultObject = this.post(ipAndPort + DaHuaIccConstant.LOGIN_URL, params);
        if ("false".equals(resultObject.getString("success"))) {
            log.error("【DahuaICC login】path:{};params:{};errMsg:{}", DaHuaIccConstant.LOGIN_URL, JSON.toJSONString(params), resultObject.getString("errMsg"));
            throw new BusinessException("DahuaICC login failed!");
        }
        String dataStr = resultObject.getString("data");
        SecurityDaHuaDTO securityDaHuaDTO = SecurityDaHuaDTO.builder()
                .userId(JSONObject.parseObject(dataStr).getString("userId"))
                .userName(loginName)
                .token(JSONObject.parseObject(dataStr).getString("access_token")).build();
        return securityDaHuaDTO;
    }

    private JSONObject post(String path, Map<String, Object> params) {
        log.info("【DahuaICC post】path:{};params:{}", path, JSON.toJSONString(params));
        String result = null;
        try {
//            Map<String, String> header = new HashMap<>();
//            header.put(DaHuaIccConstant.AUTHOR, DaHuaIccConstant.AUTHOR_VALUE);
            result = HttpRequest
                    .post(path)
//                    .addHeaders(header)
                    .body(JSON.toJSONString(params))
                    .execute()
                    .body();
        } catch (HttpException e) {
            log.error("【DahuaICC post】path:{};params:{}; request failed!", path, JSON.toJSONString(params));
            e.printStackTrace();
            throw new ApplicationException();
        }
        if (StringUtils.isEmpty(result)) {
            log.error("【DahuaICC post】path:{};params:{};result is null!", path, JSON.toJSONString(params));
            throw new BusinessException();
        }
        log.info("【DahuaICC post】path:{};params:{};result:{}", path, JSON.toJSONString(params), result);
        return JSON.parseObject(result);
    }

    public JSONObject post(String api, Map<String, Object> params, Integer projectId, Integer productId, String ipAndPort, String loginName, String password, String appId, String appSecret) {
        SecurityDaHuaDTO securityDaHuaDTO = this.getToken(projectId, productId, ipAndPort, loginName, password, appId, appSecret);
        if (securityDaHuaDTO == null) {
            log.error("【DahuaICC post】path:{};getToken fail!", api);
            return null;
        }
        log.warn(securityDaHuaDTO.getToken());
        StringBuffer pathBuffer = new StringBuffer()
                .append(ipAndPort)
                .append(api)
                .append("?userId=")
                .append(securityDaHuaDTO.getUserId())
                .append("&userName=")
                .append(securityDaHuaDTO.getUserName())
                .append("&token=")
                .append(securityDaHuaDTO.getToken());
        return this.postWithAuth(pathBuffer.toString(), params, securityDaHuaDTO);
    }
    public JSONObject put(String api, Map<String, Object> params, Integer projectId, Integer productId, String ipAndPort, String loginName, String password, String appId, String appSecret) {
        SecurityDaHuaDTO securityDaHuaDTO = this.getToken(projectId, productId, ipAndPort, loginName, password, appId, appSecret);
        if (securityDaHuaDTO == null) {
            log.error("【DahuaICC post】path:{};getToken fail!", api);
            return null;
        }
        StringBuffer pathBuffer = new StringBuffer()
                .append(ipAndPort)
                .append(api)
                .append("?userId=")
                .append(securityDaHuaDTO.getUserId())
                .append("&userName=")
                .append(securityDaHuaDTO.getUserName())
                .append("&token=")
                .append(securityDaHuaDTO.getToken());
        return this.putWithAuth(pathBuffer.toString(), params, securityDaHuaDTO);
    }

    private JSONObject putWithAuth(String path, Map<String, Object> params, SecurityDaHuaDTO securityDaHuaDTO) {
        log.info("【DahuaICC post】path:{};params:{}", path, JSON.toJSONString(params));
        String result = null;
        try {
            Map<String, String> header = new HashMap<>();
            header.put(DaHuaIccConstant.AUTHOR, "bearer " + securityDaHuaDTO.getToken());
            result = HttpRequest
                    .put(path)
                    .addHeaders(header)
                    .body(JSON.toJSONString(params))
                    .execute()
                    .body();
        } catch (HttpException e) {
            log.error("【DahuaICC post】path:{};params:{}; request failed!", path, JSON.toJSONString(params));
            e.printStackTrace();
            throw new ApplicationException();
        }
        if (StringUtils.isEmpty(result)) {
            log.error("【DahuaICC post】path:{};params:{};result is null!", path, JSON.toJSONString(params));
            throw new BusinessException();
        }
        log.info("【DahuaICC post】path:{};params:{};result:{}", path, JSON.toJSONString(params), result);
        return JSON.parseObject(result);
    }
    public JSONObject delete(String api, Map<String, Object> params, Integer projectId, Integer productId, String ipAndPort, String loginName, String password, String appId, String appSecret) {
        SecurityDaHuaDTO securityDaHuaDTO = this.getToken(projectId, productId, ipAndPort, loginName, password, appId, appSecret);
        if (securityDaHuaDTO == null) {
            log.error("【DahuaICC post】path:{};getToken fail!", api);
            return null;
        }
        log.warn(securityDaHuaDTO.getToken());
        StringBuffer pathBuffer = new StringBuffer()
                .append(ipAndPort)
                .append(api)
                .append("?userId=")
                .append(securityDaHuaDTO.getUserId())
                .append("&userName=")
                .append(securityDaHuaDTO.getUserName())
                .append("&token=")
                .append(securityDaHuaDTO.getToken());
        return this.deleteWithAuth(pathBuffer.toString(), params, securityDaHuaDTO);
    }

    private JSONObject deleteWithAuth(String path, Map<String, Object> params, SecurityDaHuaDTO securityDaHuaDTO) {
        log.info("【DahuaICC post】path:{};params:{}", path, JSON.toJSONString(params));
        String result = null;
        try {
            Map<String, String> header = new HashMap<>();
            header.put(DaHuaIccConstant.AUTHOR, "bearer " + securityDaHuaDTO.getToken());
            result = HttpRequest
                    .delete(path)
                    .addHeaders(header)
                    .body(JSON.toJSONString(params))
                    .execute()
                    .body();
        } catch (HttpException e) {
            log.error("【DahuaICC post】path:{};params:{}; request failed!", path, JSON.toJSONString(params));
            e.printStackTrace();
            throw new ApplicationException();
        }
        if (StringUtils.isEmpty(result)) {
            log.error("【DahuaICC post】path:{};params:{};result is null!", path, JSON.toJSONString(params));
            throw new BusinessException();
        }
        log.info("【DahuaICC post】path:{};params:{};result:{}", path, JSON.toJSONString(params), result);
        return JSON.parseObject(result);
    }

    private JSONObject postWithAuth(String path, Map<String, Object> params, SecurityDaHuaDTO securityDaHuaDTO) {
        log.info("【DahuaICC post】path:{};params:{}", path, JSON.toJSONString(params));
        String result = null;
        try {
            Map<String, String> header = new HashMap<>();
            header.put(DaHuaIccConstant.AUTHOR, "bearer " + securityDaHuaDTO.getToken());
            result = HttpRequest
                    .post(path)
                    .addHeaders(header)
                    .body(JSON.toJSONString(params))
                    .execute()
                    .body();
        } catch (HttpException e) {
            log.error("【DahuaICC post】path:{};params:{}; request failed!", path, JSON.toJSONString(params));
            e.printStackTrace();
            throw new ApplicationException();
        }
        if (StringUtils.isEmpty(result)) {
            log.error("【DahuaICC post】path:{};params:{};result is null!", path, JSON.toJSONString(params));
            throw new BusinessException();
        }
        if (!path.contains(DaHuaIccConstant.ADMIN_REST_URL)){
            log.info("【DahuaICC post】path:{};params:{};result:{}", path, JSON.toJSONString(params), result);
        }
        return JSON.parseObject(result);
    }
    public JSONObject upload(String api, Map<String, Object> params, Integer projectId, Integer productId, String ipAndPort, String loginName, String password, String appId, String appSecret) {
        SecurityDaHuaDTO securityDaHuaDTO = this.getToken(projectId, productId, ipAndPort, loginName, password, appId, appSecret);
        if (securityDaHuaDTO == null) {
            log.error("【DahuaICC post】path:{};getToken fail!", api);
            return null;
        }
        log.warn(securityDaHuaDTO.getToken());
        StringBuffer pathBuffer = new StringBuffer()
                .append(ipAndPort)
                .append(api)
                .append("?userId=")
                .append(securityDaHuaDTO.getUserId())
                .append("&userName=")
                .append(securityDaHuaDTO.getUserName())
                .append("&token=")
                .append(securityDaHuaDTO.getToken());
        return this.uploadWithAuth(pathBuffer.toString(), params, securityDaHuaDTO);
    }

    private JSONObject uploadWithAuth(String path, Map<String, Object> params, SecurityDaHuaDTO securityDaHuaDTO)  {
        log.info("【DahuaICC post】path:{};params:{}", path, JSON.toJSONString(params));
        String result = null;
        String imageUrl = params.get("imageUrl").toString();
        if(StringUtils.isEmpty(imageUrl)){
            return JSON.parseObject(result);
        }

        try {
            URL url = new URL(imageUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(10 * 1000);
            InputStream is = conn.getInputStream();

            //得到图片的二进制数据，以二进制封装得到数据，具有通用性
            ByteArrayOutputStream readStream = new ByteArrayOutputStream();
            byte[] buffer = new byte[6024];
            int len;
            while ((len = is.read(buffer)) != -1) {
                readStream.write(buffer, 0, len);
            }
            is.close();
            File imageFile = new File("Copy.jpg");
            FileOutputStream outStream = new FileOutputStream(imageFile);
            outStream.write(readStream.toByteArray());
            outStream.close();
            Map<String, String> header = new HashMap<>();
            header.put(DaHuaIccConstant.AUTHOR, "bearer " + securityDaHuaDTO.getToken());
            result = HttpRequest
                    .post(path)
                    .addHeaders(header)
                    .form("file", imageFile)
                    .execute()
                    .body();
        } catch (HttpException | IOException e) {
            log.error("【DahuaICC post】path:{};params:{}; request failed!", path, JSON.toJSONString(params));
            e.printStackTrace();
            //throw new ApplicationException();
        }
        if (StringUtils.isEmpty(result)) {
            log.error("【DahuaICC post】path:{};params:{};result is null!", path, JSON.toJSONString(params));
            //throw new BusinessException();
        }
        log.info("【DahuaICC post】path:{};params:{};result:{}", path, JSON.toJSONString(params), result);
        return JSON.parseObject(result);
    }

    private JSONObject get(String path) {
        String result = null;
        try {
//            Map<String, String> header = new HashMap<>();
//            header.put(DaHuaIccConstant.AUTHOR, DaHuaIccConstant.AUTHOR_VALUE);
            result = HttpRequest.get(path).execute().body();
        } catch (HttpException e) {
            log.error("【DahuaICC get】path:{}; request failed!", path);
            e.printStackTrace();
            throw new ApplicationException();
        }
        if (StringUtils.isEmpty(result)) {
            log.error("【DahuaICC get】path:{};result is null!", path);
            throw new BusinessException();
        }
        log.info("【DahuaICC get】path:{};result:{}", path, result);
        return JSON.parseObject(result);
    }

    public JSONObject get(String api, Map<String, Object> params, Integer projectId, Integer productId, String ipAndPort, String loginName, String password, String clientId, String clientSecret) {
        SecurityDaHuaDTO securityDaHuaDTO = this.getToken(projectId, productId, ipAndPort, loginName, password, clientId, clientSecret);
        if (securityDaHuaDTO == null) {
            log.error("【DahuaICC post】path:{};getToken fail!", api);
            return null;
        }
        if(params.get("id")!=null && StringUtils.isNotEmpty(params.get("id").toString()) ){
            api = api+params.get("id").toString();
        }
        StringBuffer pathBuffer = new StringBuffer()
                .append(ipAndPort)
                .append(api)
                .append("?userId=")
                .append(securityDaHuaDTO.getUserId())
                .append("&userName=")
                .append(securityDaHuaDTO.getUserName())
                .append("&token=")
                .append(securityDaHuaDTO.getToken());
        String firstKey=new String();
        if (params.keySet().toArray().length>0) {
             firstKey = String.valueOf(params.keySet().toArray()[0]);
        }
        log.info("firstKey"+firstKey);
        for (String attribute  : params.keySet() ){
            if (StringUtils.equals(firstKey,attribute)) {
                pathBuffer.append("?" + attribute + "=" + params.get(attribute));
            }else{
                pathBuffer.append("&" + attribute + "=" + params.get(attribute));
            }
        }
        return this.getWithAuth(pathBuffer.toString(), securityDaHuaDTO);
    }

    private JSONObject getWithAuth(String path, SecurityDaHuaDTO securityDaHuaDTO) {
        String result = null;
        try {
            Map<String, String> header = new HashMap<>();
            header.put(DaHuaIccConstant.AUTHOR, "bearer " + securityDaHuaDTO.getToken());
            result = HttpRequest.get(path).addHeaders(header).execute().body();
        } catch (HttpException e) {
            log.error("【DahuaICC get】path:{}; request failed!", path);
            e.printStackTrace();
            throw new ApplicationException();
        }
        if (StringUtils.isEmpty(result)) {
            log.error("【DahuaICC get】path:{};result is null!", path);
            throw new BusinessException();
        }
        log.info("【DahuaICC get】path:{};result:{}", path, result);
        return JSON.parseObject(result);
    }

    /**
     * 用于访问有params的get请求
     */
    public JSONObject getAndParams(String url, Map<String, Object> params, Integer projectId, Integer productId, String ipAndPort, String loginName, String password, String clientId, String clientSecret){
        SecurityDaHuaDTO securityDaHuaDTO = this.getToken(projectId, productId, ipAndPort, loginName, password, clientId, clientSecret);

        return this.getWithAuth(this.urlAndParanms(ipAndPort+url,params),securityDaHuaDTO);
    }

    /**
     * 将url与params进行组装
     */
    private String urlAndParanms(String url, Map<String,Object> params){
        if(params.isEmpty()){
            return url;
        }else{
            StringBuilder urlAndParams = new StringBuilder();
            urlAndParams.append(url+"?");
            params.forEach((k,v)->{
                urlAndParams.append(k).append("=").append(v).append("&");
            });
            String urlAndParamsStr = urlAndParams.toString();
            return urlAndParamsStr.substring(0,urlAndParamsStr.length()-1);
        }
    }

    public static String generateOpenCode(Integer accountId,Integer projectId){
        return accountId+"by"+projectId;
    }
}
